package com.mysql.backup;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import system.Sys_Config;
import system.queryer.MySQL_Queryer;

import com.mysql.opt.Operator;
import com.mysql.opt.ProcedureOperator;
import com.mysql.opt.TablesOperator;
import com.mysql.opt.TriggerOperator;
import com.mysql.opt.ViewsOperator;

class DataBaseBackupFactory {
	private static final String BACKUP_NAME_ALL = "[db_Name]_back_[date].sql";
	private static final String BACKUP_NAME_VIEW = "dumpViews.sql";
	private static final String BACKUP_NAME_TRIGGER = "dumpTriggers.sql";
	private static final String BACKUP_NAME_PROCEDURE = "dumpProcedures.sql";
	private static final String BACKUP_NAME_TABLE = "dumpTables.sql";

	private String encoding = "UTF-8";
	
	private Operator vwO = new ViewsOperator();
	private Operator tbO = new TablesOperator();
	private Operator prO = new ProcedureOperator();
	private Operator trO = new TriggerOperator();

	public DataBaseBackupFactory(String encoding){
		this.encoding = encoding;
	}
	
	public void doAllBack(String fileloc) throws BackupException, IOException{
		System.out.println("Starting Backup For All...");
		if(this.checkIfDir(fileloc)){
			File fi = new File(fileloc + File.separator +
					DataBaseBackupFactory.BACKUP_NAME_ALL.replace("[db_Name]", Sys_Config.DB_NAME).
					replace("[date]", new SimpleDateFormat("yyyyMMddHHmmss").format(new Date())));
			BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fi), encoding));
			bw.write(this.genHeaderCommentForAll());
			Operator.writeSql(bw, this.tbO);
			Operator.writeSql(bw, this.vwO);
			Operator.writeSql(bw, this.prO);
			Operator.writeSql(bw, this.trO);			
			bw.close();
		}else{
			throw new BackupException(fileloc + "is not an available directory");
		}		
		System.out.println("Finish Backup For All...");
	}
	
	private String genHeaderCommentForAll(){
		String header_content = "";
		header_content = Sys_Config.BACKUP_CONFIG_MAP.get("HEADER_CONTENT");
		header_content = header_content.replace("[DriverName]", Sys_Config.BACKUP_SYS_MAP.get(Sys_Config.KEY_DRIVER_NAME));	
		header_content = header_content.replace("[DriverVer]", Sys_Config.BACKUP_SYS_MAP.get(Sys_Config.KEY_DRIVER_VER));	
		header_content = header_content.replace("[ProductName]", Sys_Config.BACKUP_SYS_MAP.get(Sys_Config.KEY_PROCDUCT_NAME));	
		header_content = header_content.replace("[ProductVer]", Sys_Config.BACKUP_SYS_MAP.get(Sys_Config.KEY_PROCDUCT_VER));
		header_content = header_content.replace("[type]", "ALL");	
		header_content = header_content.replace("[date]", new Date().toString());			
		return header_content;
	}
	
	public void doBackView(String fileloc) throws BackupException {
		if(this.checkIfDir(fileloc)){
			this.vwO.dumpSql(fileloc + File.separator + BACKUP_NAME_VIEW, this.encoding);
		}else{
			throw new BackupException(fileloc + "is not an available directory");
		}
	}

	public void doBackTb(String fileloc) throws BackupException {
		if(this.checkIfDir(fileloc)){
			this.tbO.dumpSql(fileloc + File.separator + BACKUP_NAME_TABLE, this.encoding);
		}else{
			throw new BackupException(fileloc + "is not an available directory");
		}
	}

	public void doBackTrig(String fileloc) throws BackupException {
		if(this.checkIfDir(fileloc)){
			this.trO.dumpSql(fileloc + File.separator + BACKUP_NAME_TRIGGER, this.encoding);
		}else{
			throw new BackupException(fileloc + "is not an available directory");
		}
	}

	public void doBackProc(String fileloc) throws BackupException {
		if(this.checkIfDir(fileloc)){
			this.prO.dumpSql(fileloc + File.separator + BACKUP_NAME_PROCEDURE, this.encoding);
		}else{
			throw new BackupException(fileloc + "is not an available directory");
		}
	}
	
	
	public int[] executeBackupSql(String filePath, String encoding, boolean isIgnoreError){
		File sqlFile = new File(filePath);
		int ErrorCnt = 0;
		int ExecuteCnt = 0;
		Long beginTime = new Date().getTime();
		try {
			MySQL_Queryer mysqlQ = new MySQL_Queryer();
			BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(sqlFile), encoding));
			String sql = "";
			String line;
			String curObj = "";
			while((line = br.readLine())!=null){
				//info comming...
				if(line.contains("-- Obj-jdbv-r Item Seprtor")){
					ExecuteCnt++;
					try{
						if(!curObj.equalsIgnoreCase("")){
							System.out.print("Importing: " + curObj + " Result: ");
						}
						int effectedrow = mysqlQ.toUpdate(sql);
						System.out.println(effectedrow + " row effected");						
					}catch(Exception e){
						e.printStackTrace();
						ErrorCnt++;
						if(!isIgnoreError){
							br.close();							
							break;
						}
					}					
					curObj = line.replace("-- Obj-jdbv-r Item Seprtor", "");
					System.out.println("Reading: " + curObj);
					sql = "";
				}else if(line.startsWith("DROP ") && line.endsWith(";")){
					ExecuteCnt++;
					sql = line;
					try{
						System.out.print("DROP IF EXISTS: " + curObj + " Result: ");
						int effectedrow = mysqlQ.toUpdate(sql);
						System.out.println(effectedrow + " row effected");
					}catch(Exception e){
						e.printStackTrace();
						ErrorCnt++;
						if(!isIgnoreError){
							br.close();							
							break;
						}
					}
					sql = "";
				}else{
					sql += line + Operator.nextline;
				}
			}
			br.close();
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}		
		Long endTime = new Date().getTime();
		System.out.println("Finish Sql: " + sqlFile.getAbsolutePath());
		System.out.println("Total SQLs: " + ExecuteCnt);
		System.out.println("Error Count: " + ErrorCnt);
		System.out.println("Cost: " + (endTime - beginTime) + "ms");
		int[] re = {ExecuteCnt,ErrorCnt};
		return re;
	}
	
	private boolean checkIfDir(String loc){
		File fi = new File(loc);
		if(!fi.exists()){
			fi.mkdirs();
		}
		if(fi.isDirectory()){
			
			return true;
		}else{
			return false;
		}
	}
	
	
}
